﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

namespace SecurEntityLib
{
    public class DbContextHelper
    {
        public ObjectContext Context { get; set; }

        void oc_SavingChanges(object sender, EventArgs e)
        {
            Dictionary<Guid, bool> encryptedItems = new Dictionary<Guid, bool>();
            bool keepEncrypting = true;

            //
            // The encrypt loop can cause additional items (i.e. not already in the OSM) 
            // to be read from the database. If those items aren't caught in the 
            // encrypt loop, they'll be written back as plaintext. So we keep looping
            // until we don't find any cached plaintext SecurEntity objects.
            // 

            while (true == keepEncrypting)
            {
                keepEncrypting = false;
                foreach (ObjectStateEntry entry in
                    ((ObjectContext)sender).ObjectStateManager.GetObjectStateEntries(
                    EntityState.Added | EntityState.Modified))
                {
                    if (false == entry.IsRelationship &&
                        entry.Entity is SecurEntityLib.SecurEntity &&
                        false == encryptedItems.ContainsKey(
                            ((SecurEntityLib.SecurEntity)entry.Entity).SecurEntityID))
                    {
                        ((SecurEntityLib.SecurEntity)entry.Entity).Encrypt();
                        encryptedItems.Add(
                            ((SecurEntityLib.SecurEntity)entry.Entity).SecurEntityID,
                            true);
                        keepEncrypting = true;
                    }
                }
            }
        }

        void oc_ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
        {
            if (e.Entity is SecurEntityLib.SecurEntity)
            {
                ((SecurEntityLib.SecurEntity)e.Entity).Decrypt();
            }
        }

        public DbContextHelper()
        {
        }

        public DbContextHelper(DbContext db)
        {
            Context = ((IObjectContextAdapter)db).ObjectContext;
            Context.ObjectMaterialized += new ObjectMaterializedEventHandler(oc_ObjectMaterialized);
            Context.SavingChanges += new EventHandler(oc_SavingChanges);
        }
    }
}